/*
 * test_db2.cpp
 *
 *  Created on: Nov 12, 2013
 *      Author: killerg
 */






#include <unistd.h>
#include <assert.h>
#include <map>
#include "share/json/json.h"
#include "share/util.h"
#include "share/db_mgr.h"
#include "share/clock.h"

using namespace std;

static  db_mgr_t g_db;
map<db_error_t, int32_t> errmap;

int g_op_num = 0;

bool test_addview(int num, bool stale = false) {
    g_op_num = 0;
    errmap.clear();
    Json::Value obj;
    int size = 100;
    char* buffer = (char*)malloc(size);
    for (int i=0; i<size; ++i)
        buffer[i] = 'a' + i % 26;
    buffer[size-1] = 0;
    for (int i=0; i<num; ++i) {
        obj["index"] = i;
        obj["data"] = fmt_cstr("obj%d, %s", i, buffer);
        obj["randnum"] = rand() % num;

//        g_db.set(fmt_str("%d", i).c_str(), to_cstr(obj), [](lcb_error_t err){
//            g_op_num--;
//            if (err != LCB_SUCCESS) {
//                ++errmap[err];
//                printf("store error:%s", lcb_strerror(NULL, err));
//            }
//        });
//        ++g_op_num;
        const char* path = "/_design/dev_test/_view/test_view?stale=%s&full_set=true&connection_timeout=60000&limit=100&skip=0";
        char b[200];
        sprintf(b, path, stale?"true":"false");
        g_db.view(b, [](db_error_t err, const Json::Value &value){
            g_op_num--;
            if (err != DBE_Success) {
                ++errmap[err];
                printf("view error:%s", db_strerror(err));
            }
            if (!value["error"].isNull()) {
                printf("view error:%s", value["reason"].asCString());
            }
        });
        ++g_op_num;
    }
    free(buffer);

    return true;
}

bool test_view(int num) {
    g_op_num = 0;
    const char* path = "/_design/dev_test/_view/test_view?stale=false&full_set=true&connection_timeout=60000&limit=100&skip=0";
    for (int i=0; i<num; ++i) {
        g_db.view(path, [](db_error_t err, const Json::Value &value){
            g_op_num--;
            if (err != DBE_Success) {
                ++errmap[err];
                printf("view error:%s", db_strerror(err));
            }
            if (!value["error"].isNull()) {
                printf("view error:%s", value["reason"].asCString());
            }
        });
        g_op_num++;
    }
    return true;
}

bool test_add(int num, int size) {
    g_op_num = 0;
    errmap.clear();
    Json::Value obj;
    char* buffer = (char*)malloc(size);
    for (int i=0; i<size; ++i)
        buffer[i] = 'a' + i % 26;
    buffer[size-1] = 0;
    for (int i=0; i<num; ++i) {
        obj["index"] = i;
        obj["data"] = fmt_cstr("obj%d, %s", i, buffer);
        obj["randnum"] = rand() % num;

        bool res = g_db.set(fmt_str("%d", i).c_str(), obj, [](db_error_t err){
            g_op_num--;
            if (err != DBE_Success) {
                ++errmap[err];
                static bool print_err = false;
                if (!print_err) {
                    printf("store error:%s\n", db_strerror(err));
                    print_err = true;
                }
            }
        });
        if (res)
            ++g_op_num;
    }
    free(buffer);
    return true;
}

bool test_get(int num) {
    g_op_num = 0;
    errmap.clear();
    for (int i=0; i<num; ++i) {
        g_db.get(fmt_cstr("%d", i), [i](db_error_t err, const Json::Value &value){
            g_op_num--;
            if (err != DBE_Success) {
                ++errmap[err];
                printf("store error:%s\n", db_strerror(err));
            }
//            assert(0 == strcmp(obj["data"].asCString(), fmt_cstr("obj%d", i)));
        });
        g_op_num++;
    }

    return true;
}

bool test_dels(int num) {
    g_op_num = 0;
    errmap.clear();
    std::vector<std::string> keys;
    for (int i=0; i<num; ++i) {
        keys.emplace_back(fmt_cstr("%d", i));
    }
    g_db.dels(keys, [](db_error_t err, bool last){
        if (err != DBE_Success) {
//            printf("store error:%s\n", lcb_strerror(NULL, err));
            ++errmap[err];
        }
        if (last) {
            printf("finished\n");
        }
    });

    return true;
}

bool test_del(int num) {
    g_op_num = 0;
    errmap.clear();
    for (int i=0; i<num; ++i) {
        g_db.del(fmt_cstr("%d", i), [](db_error_t err){
            if (err != DBE_Success) {
                ++errmap[err];

//                printf("store error:%s\n", lcb_strerror(NULL, err));
            }
            g_op_num--;
        });
        g_op_num++;
    }

    return true;
}


bool finish = false;
void on_cc(int) {
    finish = true;
}

static int log_cb(const char* fmt, ...) {
    return 0;
}

bool test_db2(int argc, char** argv)
{
    if (argc < 3) {
        printf("cmd stage num size\n");
        return false;
    }

    int stage = atoi(argv[1]);
    int num = atoi(argv[2]);
    int size = 10;
    if (argc == 4)
        size = atoi(argv[3]);

    on_signal(SIGINT, on_cc);

    if (!g_db.init("192.168.1.3", "", "", "default")) {
        printf("db_init error\n");
        return false;
    }

    double start = my_clock_t::get_time();
    switch (stage) {
    case 0:
        test_add(num, size);
        break;
    case 1:
        test_get(num);
        break;
    case 2:
        test_dels(num);
        break;
    case 3:
        test_del(num);
        break;
    case 4:
        test_view(num);
        break;
    case 5:
        test_addview(num, size == 0);
        break;
    default:
        break;
    }

    int i=0;
    while (g_db.ok()) {
        g_db.update();
        sleep(1);
        printf("%d\n", ++i);
    }
    g_db.wait();

    g_db.destroy();

    double end = my_clock_t::get_time();
    printf("opnum:%d stage:%d num:%d %fs\n", g_op_num, stage, num, end-start);
    for (auto itr = errmap.begin(); itr != errmap.end(); ++itr) {
        printf("%d %d %s\n", itr->first, itr->second, db_strerror(itr->first));
    }

    return true;
}
